package io.github.uicdb.et.mixin;

import io.github.uicdb.et.IElementAttachment;
import io.github.uicdb.et.net.ElementAttachmentData;
import io.github.uicdb.et.net.ElementDataSerializer;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(LivingEntity.class)
public abstract class LivingEntityMixin extends Entity implements IElementAttachment {

    @Shadow
    public abstract void take(Entity entity, int amount);

    @Unique
    private static final EntityDataAccessor<ElementAttachmentData> ET_ELEMENT_KEY = SynchedEntityData.defineId(LivingEntity.class, ElementDataSerializer.INSTANCE);

    public LivingEntityMixin(EntityType<?> entityType, Level level) {
        super(entityType, level);
    }

    @Inject(method = "defineSynchedData", at = @At("TAIL"))
    private void et_inject_defineSyncedData(SynchedEntityData.Builder builder, CallbackInfo ci) {
        builder.define(ET_ELEMENT_KEY, new ElementAttachmentData());
    }

    @Override
    public void elemental_theory_setElementData(ElementAttachmentData data) {
        entityData.set(ET_ELEMENT_KEY, data);
    }

    @Override
    public ElementAttachmentData elemental_theory_getElementData() {
        return entityData.get(ET_ELEMENT_KEY);
    }

    @Inject(method = "readAdditionalSaveData", at = @At("TAIL"))
    private void et_inject_readAdditionalSaveData(CompoundTag compound, CallbackInfo ci) {
        entityData.set(ET_ELEMENT_KEY, ElementAttachmentData.CODEC.decode(NbtOps.INSTANCE, compound.getCompound("et_element")).getOrThrow().getFirst());
    }

    @Inject(method = "addAdditionalSaveData", at = @At("TAIL"))
    private void et_inject_addAdditionalSaveData(CompoundTag compound, CallbackInfo ci) {
        var tag = ElementAttachmentData.CODEC.encode(entityData.get(ET_ELEMENT_KEY), NbtOps.INSTANCE, new CompoundTag()).getOrThrow();
        compound.put("et_element", tag);
    }

    @Inject(method = "tick", at = @At("TAIL"))
    private void et_inject_tick(CallbackInfo ci) {
        entityData.set(ET_ELEMENT_KEY, entityData.get(ET_ELEMENT_KEY).tickDown());
    }
}
